const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function Promise(excute) {
  let that = this;
  that.onFulfilledFn = [];
  that.onRejectedFn = [];
  that.state = PENDING;
  function resolve(value) {
    setTimeout(function() {
        if(that.state === PENDING) {
          that.state = FULFILLED;
          that.value = value;
          that.onFulfilledFn.forEach(fn => fn(that.value))
        }else {
          throw new Error('状态不可逆，并且只可改变一次')
        }
      }, 0)

  }
  function reject(reason) {
    setTimeout(function() {
      if(that.state === PENDING) {
        that.state = REJECTED;
        that.reason = reason;
        that.onRejectedFn.forEach(fn => fn(that.reason))
      }else {
        throw new Error('状态不可逆，并且只可改变一次')
      }
    },0)

  }
  try {
    excute(resolve, reject);
  } catch (e) {
    reject(e)
  }
}
function resolvePromise(promise, x, resolve, reject) {
  if (promise === x) {
    return reject(new TypeError('x 不能与 promise 相等'));
  }
  if (x instanceof Promise) {
    if (x.state === FULFILLED) {
      resolve(x.value);
    } else if (x.state === REJECTED) {
      reject(x.reason);
    } else {
      x.then(function(y) {
        resolvePromise(promise, y, resolve, reject);
      }, reject);
    }
  } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    var executed;
    try {
      var then = x.then;
      if (typeof then === 'function') {
        then.call(
          x,
          function(y) {
            if (executed) return;
            executed = true;
            resolvePromise(promise, y, resolve, reject);
          },
          function(e) {
            if (executed) return;
            executed = true;
            reject(e);
          }
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      if (executed) return;
      executed = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}
Promise.prototype.then = function (onFulfilled, onRejected) {
  onFulfilled = typeof onFulfilled === 'function'? onFulfilled: (x) =>  x;
  onRejected = typeof onRejected === 'function'? onRejected: (e) =>  e;
  var that = this;
  var promise;
  if(that.state === FULFILLED) {
    promise = new Promise(function(resolve, reject) {
      setTimeout(() => {
        try {
          // onFulfilled(that.value)
          // console.log('that.value',that.value)
          var x = onFulfilled(that.value);
          resolvePromise(promise, x, resolve, reject);
        } catch (error) {
          reject(error)
        }
      }, 0)
    })
  }
  if(that.state === REJECTED) {
    promise = new Promise(function(resolve, reject) {
      setTimeout(() => {
        try {
          // onRejected(that.reason)
          var x = onRejected(that.reason);
          // console.log('that.value',that.value)
          resolvePromise(promise, x, resolve, reject);
        } catch (error) {
          reject(error)
        }
      }, 0)
    })
  }
  if(that.state === PENDING) {
    promise = new Promise(function(resolve, reject) {
      that.onFulfilledFn.push(function() {
        try {
          // onFulfilled(that.reason);
          var x = onFulfilled(that.value);
          // console.log('that.value',that.value)
          resolvePromise(promise, x, resolve, reject);
        } catch (error) {
          reject(error)
        }
      })
      that.onRejectedFn.push(function() {
        try {
          // onRejected(that.reason);
          var x = onRejected(that.reason);
          // console.log('that.value',that.value)
          resolvePromise(promise, x, resolve, reject);
        } catch (error) {
          reject(error)
        }
      })
    })

  }
  return promise;
}
Promise.resolve = function(value) {
  if (value instanceof Promise) {
    return value;
  }

  return new Promise(function(resolve, reject) {
    resolve(value);
  });
}
Promise.reject = function(reason) {
  return new Promise(function(resolve, reject) {
    reject(reason);
  });
}
Promise.prototype.catch = function(onRejected) {
  return this.then(null, onRejected);
}
Promise.prototype.finally = function(fn) {
  return this.then(function(value) {
    return Promise.resolve(fn()).then(function() {
      return value;
    });
  }, function(error) {
    return Promise.resolve(fn()).then(function() {
      throw error;
    });
  });
}

Promise.all = function(promiseArr) {
  return new Promise(function(resolve, reject) {
    const length = promiseArr.length;
    const result = [];
    let count = 0;
    if (length === 0) {
      return resolve(result);
    }

    for (let [i, p] of promiseArr.entries()) {
      Promise.resolve(p).then(function(data) {
        result[i] = data;
        count++;
        if (count === length) {
          resolve(result);
        }
      }, function(reason) {
        reject(reason);
      });
    }
  });
}

Promise.race = function(promiseArr) {
  return new Promise(function(resolve, reject) {
    const length = promiseArr.length;
    if (length === 0) {
      return resolve();
    }

    for (let item of promiseArr) {
      Promise.resolve(item).then(function(value) {
        return resolve(value);
      }, function(reason) {
        return reject(reason);
      });
    }
  });
}

Promise.any = function(promiseArr) {
  return new Promise(function(resolve, reject) {
    const length = promiseArr.length;
    const result = [];
    let count = 0;
    if (length === 0) {
      return resolve(result);
    }

    for (let [i, p] of promiseArr.entries()) {
      Promise.resolve(p).then((value) => {
        return resolve(value);
      }, (reason) => {
        result[i] = reason;
        count++;
        if (count === length) {
          reject(result);
        }
      });
    }
  });
}

Promise.allSettled = function(promiseArr) {
  return new Promise(function(resolve) {
    const length = promiseArr.length;
    const result = [];
    let count = 0;

    if (length === 0) {
      return resolve(result);
    } else {
      for (let [i, p] of promiseArr.entries()) {
        Promise.resolve(p).then((value) => {
          result[i] = { status: 'fulfilled', value: value };
          count++;
          if (count === length) {
            return resolve(result);
          }
        }, (reason) => {
          result[i] = { status: 'rejected', reason: reason };
          count++;
          if (count === length) {
            return resolve(result);
          }
        });
      }
    }
  });
}
// 使用 Promise.all 实现
Promise.allSettled = function(promises) {
  // 也可以使用扩展运算符将 Iterator 转换成数组
  // const promiseArr = [...promises]
  const promiseArr = Array.from(promises)
  return Promise.all(promiseArr.map(p => Promise.resolve(p).then(res => {
    return { status: 'fulfilled', value: res }
  }, error => {
    return { status: 'rejected', reason: error }
  })));
};


